package interfaces.hud.pilot;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import logic.common.missions.Mission;
import logic.common.player.Player;
import logic.common.player.playerListeners.MissionActivatedEvent;
import logic.common.player.playerListeners.PlayerMissionListener;
import logic.common.player.playerListeners.PlayerTeamListener;
import logic.common.team.Team;
import logic.common.team.teamListeners.MissionAddedEvent;
import logic.common.team.teamListeners.MissionCompletedEvent;
import logic.common.team.teamListeners.MissionDeletedEvent;
import logic.common.team.teamListeners.TeamMissionListener;
import main.InitGame;
import main.listeners.listenerClasses.LanguageListener;

import org.fenggui.binding.render.ImageFont;
import org.fenggui.util.Color;

import interfaces.GUISource;
import interfaces.hud.BasicHUD;
import interfaces.hud.spectate.SpectateChangeEvent;
import interfaces.hud.spectate.SpectateListener;
import interfaces.hud.spectate.SpectateWidget;
import interfaces.superWidgets.InterfaceLabel;
import interfaces.superWidgets.InterfaceWindow;
import interfaces.superWidgets.StaticContent;
import interfaces.superWidgets.UpdateWidget;

public class MissionContent extends InterfaceWindow implements UpdateWidget, SpectateWidget {
	
	private static final float MAX_TIME = 2.5f;
	
	private final Color LIST_COLOR = Color.BLACK;
	private final Color MARKED_COLOR = Color.BLUE;
	
	private StaticContent missionListContent;
	private InterfaceLabel activeMissionLabel, markedLabel;
	private int labelHeight, missionIndex;
	private Player player;
	private List<InterfaceLabel> missionLabels;
	private HashMap<InterfaceLabel, Mission> missionLabelMap;
	private float currentTime;
	private boolean toggled, activatedHere;
	private ImageFont labelFont;
	private BasicHUD hud;
	private TeamMissionListener teamMissionListener;
	private PlayerMissionListener missionListener;
	
	public MissionContent(final BasicHUD hud) {
		super(false, "");
		this.hud = hud;
		
		labelHeight = hud.getHeight() / 25;
		
		labelFont = GUISource.smallFont;
		
		int width = hud.getWidth() / 5;
		int height = labelHeight;
		int y = hud.getHeight() - height;
		
		setSize(width, height);
		setXY(0, y);
		
		activeMissionLabel = new InterfaceLabel(labelFont);
		activeMissionLabel.setXY(0, 0);
		activeMissionLabel.setSize(getWidth(), labelHeight);
		GUISource.setTextColor(activeMissionLabel, MARKED_COLOR);
		
		missionListContent = new StaticContent(width, labelHeight, 0, 0);
		
		missionLabels = new ArrayList<InterfaceLabel>();
		missionLabelMap = new HashMap<InterfaceLabel, Mission>();
		
		currentTime = MAX_TIME;
		
		player = hud.getIngameState().getPlayer();
		teamMissionListener = new TeamMissionListener() {
			@Override
			public void missionDeleted(MissionDeletedEvent mission) {
				setPlayer(player);
			}
			
			@Override
			public void missionCompleted(MissionCompletedEvent event) {
				buildMissionListContent();
			}
			
			@Override
			public void missionAdded(MissionAddedEvent event) {
				buildMissionListContent();
			}
		};
		hud.addListener(player.getTeam(), teamMissionListener);
		
		missionListener = new PlayerMissionListener() {
			@Override
			public void missionActivated(MissionActivatedEvent event) {
				if(!activatedHere) setPlayer(player);
			}
		};
		
		hud.addListener(player, missionListener);
		
		hud.addListener(player, new PlayerTeamListener() {
			@Override
			public void teamChanged(Team newTeam) {
				player.getEnemyTeam().removeMissionListener(teamMissionListener);
				hud.addListener(newTeam, teamMissionListener);
				
				player.setActiveMission(newTeam.getMissions().get(0));
				
				setPlayer(player);
			}
			
			@Override
			public void teamChangeFailed() {}
		});
		
		InitGame.get().addLanguageListener(new LanguageListener() {
			@Override
			public void languageChanged() {
				changeLanguage();
			}
		});
		
		if(!player.getTeam().getMissions().isEmpty()) setPlayer(player);
	}
	
	private void setPlayer(Player newPlayer) {		
		player = newPlayer;
		
		buildMissionListContent();
		
		if(markedLabel != null) activeMissionLabel.setText(markedLabel.getText());
		addWidget(activeMissionLabel);
		
		layout();
	}
	
	private void buildMissionListContent() {
		missionListContent.removeAllWidgets();
		missionLabelMap.clear();
		missionLabels.clear();
		
		Team team = player.getTeam();
		missionListContent.setHeight(labelHeight * team.getMissions().size());
		int i = 0;
		for(Mission mission : team.getMissions()) {
			InterfaceLabel label = new InterfaceLabel(mission.getDescription(), labelFont);
			label.setSize(missionListContent.getWidth(), labelHeight);
			label.setXY(0, i * labelHeight);
			GUISource.setTextColor(label, LIST_COLOR);
			
			if(mission == player.getActiveMission()) {
				setMarkedLabel(label);
				missionIndex = i;
			}
			
			missionLabels.add(label);
			missionLabelMap.put(label, mission);
			missionListContent.addWidget(label);
			
			i++;
		}
	}
	
	public void toggleMissions() {
		missionIndex++;
		if(missionIndex >= missionLabels.size()) missionIndex = 0;
		
		if(markedLabel != null) GUISource.setTextColor(markedLabel, LIST_COLOR);
		
		setMarkedLabel(missionLabels.get(missionIndex));
		
		activatedHere = true;
		player.setActiveMission(missionLabelMap.get(markedLabel));
		activatedHere = false;
		
		removeWidget(activeMissionLabel);
		setHeight(missionListContent.getHeight());
		setY(hud.getHeight() - getHeight());
		addWidget(missionListContent);
		
		layout();
		
		toggled = true;
		currentTime = 0f;
	}
	
	private void setMarkedLabel(InterfaceLabel label) {
		markedLabel = label;
		if(markedLabel != null) GUISource.setTextColor(markedLabel, MARKED_COLOR);
	}
	
	protected void changeLanguage() {
		setPlayer(player);
	}
	
	@Override
	public void update(float time) {
		if(toggled) {
			if(currentTime < MAX_TIME) currentTime += time;
			else {
				toggled = false;
				
				activeMissionLabel.setText(markedLabel.getText());
				removeWidget(missionListContent);
				addWidget(activeMissionLabel);
				
				setHeight(activeMissionLabel.getHeight());
				setY(hud.getHeight() - getHeight());
				
				layout();
			}
		}
	}
	
	@Override
	public SpectateListener getSpectateListener() {
		return new SpectateListener() {
			@Override
			public void spectating(SpectateChangeEvent event) {
				setPlayer(event.getWatchedPlayer());
			}
		};
	}
}